﻿/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using moose.irc.extension;

namespace moose.irc.actions {
    
    [CLSCompliant(true)]
    [Action(Type = ActionTypes.Command, 
        Name = "moose-std-cmd-connectpack-connect", 
        Description = "Extended Connect, with Connection Pack, provides support for more conncetion options, including the server database.", 
        Version = "0.1", 
        Author = "Mike MacKenzie-Jamer<email:mikejamer@gmail.com")]
    [Extends(BaseType=typeof(moose.irc.actions.commands.ConnectCommand))]
    public sealed class ConnectCommand : IrcAction {

        public ConnectCommand()
            : base() {
            return;
        }


        public ConnectCommand(IrcAction owner)
            : base(owner) {
            return;
        }

        #region [Action Overrides]

        /// <summary>
        /// Valid States
        /// </summary>
        /// <returns>States that are valid to connect from</returns>
        public override IrcSessionStates valid_states() {
            return IrcSessionStates.Disconnected | IrcSessionStates.None;
        }

        /// <summary>
        /// Actual Action Implementation
        /// </summary>
        /// <param name="session">reference to the session</param>
        /// <param name="message">reference to message instruction</param>
        public override void action(IrcSession session, IrcMessage message) {
            XmlDocument xdoc_groups = new XmlDocument();
            XmlDocument xdoc_servers = new XmlDocument();
            
            if (message.Arguments.Length == 1) {
                session.notify_event(IrcEvent.createEchoEvent("-:Connect-Pack:- Attempting to connect to network: " + message.Arguments[0]));
                xdoc_groups.Load(Environment.CurrentDirectory + "/configuration/servergroups.xml");
                xdoc_servers.Load(Environment.CurrentDirectory + "/configuration/servers.xml");

                XmlNode group_node = xdoc_groups.SelectSingleNode("/groups/group[@name=\"" + message.Arguments[0] + "\"]");
                if (group_node == null) {
                    session.notify_event(IrcEvent.createEchoEvent("-:Connect-Pack:- Invalid Group Name: " + message.Arguments[0]));
                    return;
                }

                XmlNodeList server_nodes = xdoc_servers.SelectNodes("/servers/server[@group=\"" + message.Arguments[0] + "\"]");
                foreach (XmlNode server_node in server_nodes) {
                    if (session.SessionState == IrcSessionStates.Connected)
                        return;
                    string base_connect_command = "SERVER " + server_node.Attributes["host"].Value + " ";
                    foreach (string port in available_ports(server_node.Attributes["ports"].Value)) {
                        IrcMessage connect_message = new IrcMessage(base_connect_command + port);
                        base_action(session, connect_message);
                        if (session.SessionState == IrcSessionStates.Connected)
                            return;
                    }
                }
            } else {
                base_action(session, message);
            }
            return;
        }

        #endregion

        #region [Helper Methods]

        /// <summary>
        /// Just computes available ports
        /// </summary>
        /// <param name="port_string">string containing abailable ports</param>
        /// <returns>collection of available ports</returns>
        private string[] available_ports(string port_string) {
            List<string> ret = new List<string>();
            string[] strTok = port_string.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string port in strTok) {
                try {
                    if (!strTok.Contains("-")) {
                        ret.Add(port);
                        continue;
                    }

                    string[] group = port.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = int.Parse(group[0]); i <= int.Parse(group[1]); i++) {
                        ret.Add(i.ToString());
                    }
                } catch (Exception) {
                    continue; //Just ignore failures...
                }
            }
            return ret.ToArray();
        }

        #endregion


    }
}

